home *** CD-ROM | disk | FTP | other *** search
Text File | 1995-11-05 | 24.3 KB | 1,005 lines | [TEXT/CWIE] |
- //////////
- //
- // Refractor 1.0
- // ©1995 Steven J. Bushell
- //
- // Refractor displays a moving circle of translated pixels
- // around the desktop, giving the appearance of a refractive
- // objects of different shapes floating through the air.
- //
- // To keep the speed of the animation high, the pixel
- // translations are precalculated and stored in an array
- // of offsets. The only calculation that is truly done
- // on the fly is finding the new offset pixels from a pair
- // of precomputed offsets in the X,Y plane.
- //
- // The motion portions of this code, as well as the basic
- // framework, are based loosely on "Bouncing Ball", by
- // Patrick C. Beard and Bruce Burkhalter. Bouncing Ball
- // is distributed as sample code on the Code Warrior 7.0
- // CD-ROM. The rest of the code is copyright Steven J. Bushell,
- // all rights reserved.
- //
- // Oh yeah - although I am loathe to admit it, the idea for
- // this module originally came from Windows 95.
- //
- //////////
-
- #include "GraphicsModule_Types.h"
- #include "Refractor.h"
- #include <math.h>
-
- // The real meat.
- void OffsetBits (RStoragePtr rStorage, PixMapHandle, PixMapHandle, Rect *);
- void InitializeOffsetBuffer (RStoragePtr rStorage, GMParamBlockPtr params);
-
- // Offscreen support routines.
- PixMapHandle BeginOffscreenDrawing (RStoragePtr rStorage, GWorldPtr world);
- PixMapHandle HoldOffscreenPix (RStoragePtr rStorage, GWorldPtr world);
- void ReleaseOffscreenPix (RStoragePtr rStorage);
- void EndOffscreenDrawing (RStoragePtr rStorage);
-
- // Utility routines.
- short random (short lower, short upper);
- void CleanUp (RStorage** storage);
- Fixed RandomAngle (short lower, short upper);
- void WatchCursor (void);
-
- static Boolean DemoMode (GMParamBlockPtr params)
- {
- // If the demo rect area isn't empty, we're in demo mode.
-
- return !EmptyRect (¶ms -> demoRect);
- }
-
- static void SetRandomDirection (RStoragePtr rStorage)
- {
- rStorage -> travelAngle = RandomAngle (10, 80);
- rStorage -> travelSin = Frac2Fix (FracSin (rStorage -> travelAngle));
- rStorage -> travelCos = Frac2Fix (FracCos (rStorage -> travelAngle));
- }
-
- static void TravelToSlopRect (RStoragePtr rStorage)
- {
- rStorage -> slopRect = rStorage -> travelRect;
- InsetRect (&rStorage -> slopRect, - maxSlopSize, - maxSlopSize);
- }
-
- OSErr DoInitialize (Handle *storage, RgnHandle /*blankRgn*/, GMParamBlockPtr params)
- {
- Handle h;
- RStoragePtr rStorage;
- StringPtr errStr;
- StringPtr unkErrStr = "\pRefractor: Sorry, this module cannot run on this machine.";
- StringPtr procErrStr = "\pRefractor: Sorry, a 68020 or later processor is required to run this module.";
- StringPtr sysVErrStr = "\pRefractor: Sorry, System 7 or later is required to run this module.";
- StringPtr mmErrStr = "\pRefractor: Sorry, this module does not run under MultiModule.";
- StringPtr colorQDErrStr = "\pRefractor: Sorry, Color Quickdraw must be present to run this module.";
- StringPtr memErrStr = "\pRefractor: Sorry, out of memory. Please make the size smaller.";
- StringPtr demoErrStr = "\pRefractor: Sorry, not enough memory to run in demo mode.";
-
- *storage = nil;
-
- do
- {
- // if color quickdraw is not available, chastise user.
- if (!params -> colorQDAvail)
- {
- errStr = colorQDErrStr;
- break;
- }
-
- #if !powerc
- // If we're not on at least a 68020 with System 7, get the hell out.
- // PowerPC code always has this requirement satisfied
- // so we only compile it for 68k.
- // (Gestalt glue is supplied in MacOS.lib.)
- long result;
- OSErr err = Gestalt (gestaltProcessorType, &result);
- if (err != noErr)
- {
- errStr = unkErrStr;
- break;
- }
-
- if ((result == gestalt68000) || (result == gestalt68010))
- {
- errStr = procErrStr;
- break;
- }
-
- err = Gestalt (gestaltSystemVersion, &result);
- if (err != noErr)
- {
- errStr = unkErrStr;
- break;
- }
-
- if (result < 0x0700L)
- {
- errStr = sysVErrStr;
- break;
- }
- #endif
-
- // We don't allow MultiModule operation
- // because we don't work correctly in it.
- // (Because AD doesn't set up the blankRegion correctly
- // during MultiModule.)
- if (params -> systemConfig & MultiModuleRunning)
- {
- errStr = mmErrStr;
- break;
- }
-
- // Create handle to hold all our goodies.
- h = NewHandleClear (sizeof(RStorage));
- if (!h)
- {
- errStr = memErrStr;
- break;
- }
-
- // store a reference to our storage where AD can keep it.
- *storage = h;
-
- // Lock handle while it's being used.
- HLockHi (h);
- rStorage = (RStoragePtr)*h;
-
- // Get the size from the second slider in the ui.
- long boxSize = (params -> controlValues[1] * maxBoxSize) / 100;
- if (boxSize < 16)
- boxSize = 16;
- rStorage -> travelRect.right = rStorage -> travelRect.left + boxSize;
- rStorage -> travelRect.bottom = rStorage -> travelRect.top + boxSize;
-
- // Set up basic Rects.
- long allocSize = DemoMode (params) ? maxBoxSize : boxSize;
- SetRect (&rStorage -> travelRect, 0, 0, allocSize, allocSize);
- TravelToSlopRect (rStorage);
- rStorage -> oldSlopRect = rStorage -> slopRect;
-
- // Allocate GWorlds.
- QDErr qdErr;
- qdErr = NewGWorld (&rStorage -> srcWorld, 32, &rStorage -> slopRect, nil, nil, 0);
- if (!rStorage -> srcWorld || qdErr)
- {
- qdErr = NewGWorld (&rStorage -> srcWorld, 32, &rStorage -> slopRect, nil, nil, useTempMem);
- if (!rStorage -> srcWorld || qdErr)
- {
- errStr = DemoMode (params) ? demoErrStr : memErrStr;
- break;
- }
- }
-
- qdErr = NewGWorld (&rStorage -> dstWorld, 32, &rStorage -> slopRect, nil, nil, 0);
- if (!rStorage -> dstWorld || qdErr)
- {
- qdErr = NewGWorld (&rStorage -> dstWorld, 32, &rStorage -> slopRect, nil, nil, useTempMem);
- if (!rStorage -> dstWorld || qdErr)
- {
- errStr = DemoMode (params) ? demoErrStr : memErrStr;
- break;
- }
- }
-
- // Allocate offset buffer.
- rStorage -> offsetBuffer = NewHandleClear (allocSize * allocSize * sizeof (short) * 2L);
- if (!rStorage -> offsetBuffer)
- {
- errStr = DemoMode (params) ? demoErrStr : memErrStr;
- break;
- }
- HLock (rStorage -> offsetBuffer);
-
- rStorage -> drawRgn = NewRgn ();
- if (!rStorage -> drawRgn)
- {
- errStr = DemoMode (params) ? demoErrStr : memErrStr;
- break;
- }
-
- rStorage -> oldDrawRgn = NewRgn ();
- if (!rStorage -> oldDrawRgn)
- {
- errStr = DemoMode (params) ? demoErrStr : memErrStr;
- break;
- }
-
- // Set up initial conditions.
- SetRect (&rStorage -> travelRect, 0, 0, boxSize, boxSize);
- OffsetRect (&rStorage -> travelRect, maxSlopSize, maxSlopSize);
- TravelToSlopRect (rStorage);
- rStorage -> oldSlopRect = rStorage -> slopRect;
-
- rStorage -> hDir = 1;
- rStorage -> vDir = 1;
- SetRandomDirection (rStorage);
-
- rStorage -> timeToReselect = 0;
- rStorage -> needToUpdate = 0;
- rStorage -> lastTouch = 0UL;
- rStorage -> timeToChange = 0;
-
- {
- // Initialize Source GWorld.
- PixMapHandle gwPmh;
- gwPmh = BeginOffscreenDrawing (rStorage, rStorage -> srcWorld);
- if (gwPmh)
- {
- SetOrigin (rStorage -> slopRect.left, rStorage -> slopRect.top);
- CopyBits (¶ms -> qdGlobalsCopy -> qdThePort -> portBits,
- (BitMapPtr)*gwPmh,
- &rStorage -> slopRect,
- &rStorage -> slopRect,
- srcCopy, nil);
- }
-
- EndOffscreenDrawing (rStorage);
- }
-
- {
- // Initialize style selection and offset buffer.
- short style = params -> controlValues[2];
- rStorage -> refractorStyle = style;
- InitializeOffsetBuffer (rStorage, params);
- }
-
- // unlock storage handle.
- HUnlock(h);
-
- // Success!
- return noErr;
-
- } while (false);
-
- // If we're here, something went wrong. Clean up and get out.
- BlockMove (errStr, params -> errorMessage, errStr[0] + 1);
- CleanUp ((RStorageHandle)*storage);
- SysBeep (0);
-
- return ModuleError;
- }
-
- // Recovery zone - called if anything fails.
- void CleanUp (RStorage **storage)
- {
- if (storage)
- {
- RStorage *rStorage;
-
- HLock((Handle)storage);
- rStorage = *storage;
-
- if (rStorage -> srcWorld)
- {
- DisposeGWorld (rStorage -> srcWorld);
- rStorage -> srcWorld = nil;
- }
-
- if (rStorage -> dstWorld)
- {
- DisposeGWorld (rStorage -> dstWorld);
- rStorage -> dstWorld = nil;
- }
-
- if (rStorage -> offsetBuffer)
- {
- DisposeHandle (rStorage -> offsetBuffer);
- rStorage -> offsetBuffer = nil;
- }
-
- if (rStorage -> drawRgn)
- {
- DisposeRgn (rStorage -> drawRgn);
- rStorage -> drawRgn = nil;
- }
-
- if (rStorage -> oldDrawRgn)
- {
- DisposeRgn (rStorage -> oldDrawRgn);
- rStorage -> oldDrawRgn = nil;
- }
-
- DisposHandle((Handle)storage);
- }
- }
-
- // Hereafter we can safely assume we're on a 68020 or better.
- #if !powerc
- #pragma code68020 on
- #endif
-
- OSErr DoBlank (Handle /*storage*/, RgnHandle /*blankRgn*/, GMParamBlockPtr params)
- {
- long brightness = (params -> controlValues[3] * 256) / 100;
-
- params -> brightness = brightness;
-
- return noErr;
- }
-
- OSErr DoDrawFrame (Handle storage, RgnHandle blankRgn ,GMParamBlockPtr params)
- {
- RStoragePtr rStorage; // to hold dereferenced storage handle
-
- // lock our storage down so we can dereference it for faster access
- HLock (storage);
- rStorage = (RStoragePtr) *storage;
-
- // This is all that's necessary to control the brightness slider.
- long brightness = (params -> controlValues[3] * 256) / 100;
- params -> brightness = brightness;
-
- // Get the size from the second slider in the ui.
- // Check it agains the current setting to see if we need resizing.
- long boxSize = (params -> controlValues[1] * maxBoxSize) / 100;
-
- // Don't let it get too small.
- if (boxSize < 16)
- boxSize = 16;
-
- if (boxSize != rStorage -> travelRect.right - rStorage -> travelRect.left)
- {
- rStorage -> lastTouch = TickCount ();
-
- if (rStorage -> needToUpdate == 0)
- {
- // The size has changed so put the original screen bits back.
- PixMapHandle srcPmh;
- srcPmh = BeginOffscreenDrawing (rStorage, rStorage -> srcWorld);
- if (srcPmh)
- {
- EndOffscreenDrawing (rStorage);
- if (LockPixels (srcPmh))
- {
- CopyBits ((BitMapPtr)*srcPmh,
- ¶ms -> qdGlobalsCopy -> qdThePort -> portBits,
- &rStorage -> slopRect,
- &rStorage -> slopRect,
- srcCopy, blankRgn);
- UnlockPixels (srcPmh);
- }
- }
- }
-
- // Flag a size update for the next time through.
- // (It's not done immediately so the user can
- // move the slider smoothly.)
- rStorage -> needToUpdate = 1;
-
- // Set the new size.
- rStorage -> travelRect.right = rStorage -> travelRect.left + boxSize;
- rStorage -> travelRect.bottom = rStorage -> travelRect.top + boxSize;
-
- // See if we're going to hang out of our drawing region.
- Rect bBox = (*blankRgn) -> rgnBBox;
- Rect newRect = rStorage -> travelRect;
-
- // If we are hanging out, put us back in.
- if (newRect.bottom > bBox.bottom)
- {
- OffsetRect (&rStorage -> travelRect, 0, bBox.bottom - newRect.bottom);
- }
-
- if (newRect.right > bBox.right)
- {
- OffsetRect (&rStorage -> travelRect, bBox.right - newRect.right, 0);
- }
-
- TravelToSlopRect (rStorage);
- rStorage -> oldSlopRect = rStorage -> slopRect;
- HUnlock (storage);
- return noErr;
- }
-
- // Do the flagged update.
- if (rStorage -> needToUpdate)
- {
- // But only if a half-second has gone by.
- // This is the key to the smooth slider action.
- if (TickCount () - rStorage -> lastTouch > 30UL)
- {
- // Reset for next resize.
- rStorage -> lastTouch = 0UL;
- InitializeOffsetBuffer (rStorage, params);
- rStorage -> needToUpdate = 0;
-
- {
- // Copy bits from screen into screen buffer.
- PixMapHandle gwPmh;
- gwPmh = BeginOffscreenDrawing (rStorage, rStorage -> srcWorld);
- if (gwPmh)
- {
- SetOrigin (rStorage -> slopRect.left, rStorage -> slopRect.top);
- CopyBits (¶ms -> qdGlobalsCopy -> qdThePort -> portBits,
- (BitMapPtr)*gwPmh,
- &rStorage -> slopRect,
- &rStorage -> slopRect,
- srcCopy, blankRgn);
- }
-
- EndOffscreenDrawing (rStorage);
- }
- }
- else
- {
- HUnlock (storage);
- return noErr;
- }
- }
-
- // Reinitialize offset buffer if the popup has changed,
- // or if we've rebounded 12 times.
- short style = params -> controlValues[2];
- if ((style != rStorage -> refractorStyle)
- || ((rStorage -> refractorStyle == 1) && (rStorage -> timeToReselect >= 12)))
- {
- rStorage -> timeToReselect = 0;
- rStorage -> refractorStyle = style;
- InitializeOffsetBuffer (rStorage, params);
- }
-
- // And now for the actual animation...
-
- // Get the source world PixMap.
- PixMapHandle srcPmh, dstPmh;
- srcPmh = BeginOffscreenDrawing (rStorage, rStorage -> srcWorld);
- if (srcPmh)
- {
- EndOffscreenDrawing (rStorage);
- if (LockPixels (srcPmh))
- {
- dstPmh = BeginOffscreenDrawing (rStorage, rStorage -> dstWorld);
- if (dstPmh)
- {
- // Copy the pixels from the screen buffer to the drawing buffer.
- SetOrigin (rStorage -> slopRect.left, rStorage -> slopRect.top);
- RectRgn (rStorage -> drawRgn, &rStorage -> slopRect);
- RectRgn (rStorage -> oldDrawRgn, &rStorage -> travelRect);
- XorRgn (rStorage -> drawRgn, rStorage -> oldDrawRgn, rStorage -> drawRgn);
- CopyBits ( (BitMapPtr)*srcPmh,
- (BitMapPtr)*dstPmh,
- &rStorage -> slopRect,
- &rStorage -> slopRect,
- srcCopy, rStorage -> drawRgn);
-
- // Move those pixels around!
- OffsetBits (rStorage,
- srcPmh,
- dstPmh,
- &rStorage -> travelRect);
- }
-
- EndOffscreenDrawing (rStorage);
- }
-
- UnlockPixels (srcPmh);
-
- // Spit the results back to the screen.
- if (LockPixels (dstPmh))
- {
- CopyBits ((BitMapPtr)*dstPmh,
- ¶ms -> qdGlobalsCopy -> qdThePort -> portBits,
- &rStorage -> slopRect,
- &rStorage -> slopRect,
- srcCopy, blankRgn);
- UnlockPixels (dstPmh);
- }
-
- // Pick a new direction if we've rebounded 8 times.
- if (rStorage -> timeToChange > 8)
- {
- rStorage -> timeToChange = 0;
- SetRandomDirection (rStorage);
- }
-
- // Calc x and y components of velocity.
- Fixed speed = Long2Fix (params -> controlValues[0]);
- long hSpeed = Fix2Long (FixMul (speed, rStorage -> travelCos));
- long vSpeed = Fix2Long (FixMul (speed, rStorage -> travelSin));
-
- hSpeed = (hSpeed * rStorage -> hDir * maxSlopSize) / 100;
- vSpeed = (vSpeed * rStorage -> vDir * maxSlopSize) / 100;
-
- rStorage -> oldSlopRect = rStorage -> slopRect;
-
- // Try to move box to new location.
- Rect bBox = (*blankRgn) -> rgnBBox;
- Rect newRect = rStorage -> travelRect;
- OffsetRect (&newRect, hSpeed, vSpeed);
-
- // Take care of wall collisions.
- if ((newRect.top < bBox.top) || (newRect.bottom > bBox.bottom))
- {
- rStorage -> vDir = - rStorage -> vDir;
- vSpeed = - vSpeed;
- rStorage -> timeToChange ++;
- rStorage -> timeToReselect ++;
- }
-
- if ((newRect.left < bBox.left) || (newRect.right > bBox.right))
- {
- rStorage -> hDir = - rStorage -> hDir;
- hSpeed = - hSpeed;
- rStorage -> timeToChange ++;
- rStorage -> timeToReselect ++;
- }
-
- // Register the movement.
- OffsetRect (&rStorage -> travelRect, hSpeed, vSpeed);
- TravelToSlopRect (rStorage);
-
- // Update the screen buffer.
- srcPmh = BeginOffscreenDrawing (rStorage, rStorage -> srcWorld);
- if (srcPmh)
- {
- SetOrigin (rStorage -> slopRect.left, rStorage -> slopRect.top);
-
- CopyBits ((BitMapPtr)*srcPmh,
- (BitMapPtr)*srcPmh,
- &rStorage -> slopRect,
- &rStorage -> oldSlopRect,
- srcCopy, nil);
-
- RectRgn (rStorage -> drawRgn, &rStorage -> slopRect);
- RectRgn (rStorage -> oldDrawRgn, &rStorage -> oldSlopRect);
- DiffRgn (rStorage -> drawRgn, rStorage -> oldDrawRgn, rStorage -> drawRgn);
-
- // Don't try to copy from space outside of what AD tells us we can have.
- SectRgn (blankRgn, rStorage -> drawRgn, rStorage -> drawRgn);
- CopyBits (¶ms -> qdGlobalsCopy -> qdThePort -> portBits,
- (BitMapPtr)*srcPmh,
- &rStorage -> slopRect,
- &rStorage -> slopRect,
- srcCopy, rStorage -> drawRgn);
- }
-
- EndOffscreenDrawing (rStorage);
- }
-
- HUnlock (storage);
-
- return noErr;
- }
-
- OSErr DoClose (Handle storage, RgnHandle /*blankRgn*/, GMParamBlockPtr /*params*/)
- {
- RStorage **rStorage = (RStorage **)storage;
-
- // Clean up the mess we made.
- CleanUp (rStorage);
-
- return noErr;
- }
-
- OSErr DoSetUp (RgnHandle /*blankRgn*/, short message, GMParamBlockPtr /*params*/)
- {
- // DoSetUp is not needed.
-
- switch (message)
- {
- default:
- break;
- }
-
- return noErr;
- }
-
- // Cool Utes.
-
- short random (short lower, short upper)
- {
- // A nice func to return a random short between lower and upper.
- short r = Random ();
-
- if (r < 0)
- r = - r;
-
- return lower + r % (upper - lower + 1);
- }
-
- Fixed RandomAngle (short lower, short upper)
- {
- // Returns in Fixed notation a random angle
- // between lower and upper (which are in degrees).
- const Fixed PI_OVER_4 = 0xC910L; // PI/4 expressed in fixed point.
-
- return FixDiv(FixMul(Long2Fix(random(lower, upper)), PI_OVER_4), Long2Fix(45));
- }
-
- void WatchCursor (void)
- {
- // Sets the cursor to the watch.
- CursHandle cursor = GetCursor (watchCursor);
-
- if (cursor)
- {
- SetCursor (*cursor);
- ReleaseResource ((Handle)cursor);
- }
- }
-
- // Offscreen drawing utilities.
-
- PixMapHandle
- BeginOffscreenDrawing (RStoragePtr rStorage, GWorldPtr world)
- {
- // Called to prepare a GWorld for drawing.
- // Should be followed by HoldOffscreenPix.
-
- GetGWorld (&rStorage -> savedCPort, &rStorage -> savedGDevice);
- SetGWorld (world, nil);
-
- return HoldOffscreenPix (rStorage, world);
- }
-
- PixMapHandle
- HoldOffscreenPix (RStoragePtr rStorage, GWorldPtr world)
- {
- // Locks the pixels in the given PixMap for drawing.
-
- rStorage -> worldPixels = GetGWorldPixMap (world);
-
- return (LockPixels (rStorage -> worldPixels))
- ? rStorage -> worldPixels
- : nil;
- }
-
- void
- ReleaseOffscreenPix (RStoragePtr rStorage)
- {
- // Unlocks the pixels in the given PixMap.
-
- if (rStorage -> worldPixels)
- {
- UnlockPixels (rStorage -> worldPixels);
- rStorage -> worldPixels = nil;
- }
- }
-
- void
- EndOffscreenDrawing (RStoragePtr rStorage)
- {
- // Indicates we're done drawing in this GWorld.
-
- ReleaseOffscreenPix (rStorage);
-
- SetGWorld (rStorage -> savedCPort, rStorage -> savedGDevice);
- }
-
- void
- OffsetBits (RStoragePtr rStorage, PixMapHandle srcPmh, PixMapHandle dstPmh, Rect *r)
- {
- // The offset array contains pairs of short integers, one pair
- // for each pixel. The pair represents an offset in the X and Y
- // direction where the pixel for a given location will come from.
-
- // This routine runs through each offset pair in the array and
- // finds the appropriate pixel at that relative offset in the
- // source PixMap to put in the destination PixMap.
-
- long srcRowBytes = (*srcPmh) -> rowBytes & 0x3fffL;
- long dstRowBytes = (*dstPmh) -> rowBytes & 0x3fffL;
-
- unsigned long srcPixBuf = (unsigned long) GetPixBaseAddr (srcPmh);
- unsigned long dstPixBuf = (unsigned long) GetPixBaseAddr (dstPmh);
-
- // Move pix pointers to the start of their data.
- srcPixBuf += (r -> top - (*srcPmh) -> bounds.top) * srcRowBytes
- + (r -> left - (*srcPmh) -> bounds.left) * 4L;
- dstPixBuf += (r -> top - (*dstPmh) -> bounds.top) * dstRowBytes
- + (r -> left - (*dstPmh) -> bounds.left) * 4L;
-
- short *offsetArray = (short *)*rStorage -> offsetBuffer;
- long tileHeight = r -> bottom - r -> top;
- long tileWidth = r -> right - r -> left;
-
- unsigned long srcPixPtr = srcPixBuf,
- dstPixPtr = dstPixBuf;
- short hOffset, vOffset;
- long pixel;
-
- for (long row = 0; row < tileHeight; row ++)
- {
- srcPixPtr = srcPixBuf;
- dstPixPtr = dstPixBuf;
-
- for (long col = 0; col < tileWidth; col ++)
- {
- hOffset = *(offsetArray ++);
- vOffset = *(offsetArray ++);
-
- pixel = *(long *)(srcPixPtr + vOffset * srcRowBytes + hOffset * 4);
- *(long *)dstPixPtr = pixel;
-
- srcPixPtr += 4;
- dstPixPtr += 4;
- }
-
- srcPixBuf += srcRowBytes;
- dstPixBuf += dstRowBytes;
- }
- }
-
- void
- InitializeOffsetBuffer (RStoragePtr rStorage, GMParamBlockPtr params)
- {
- // This routine calculates the values for the offset array,
- // which contains a pair of short integers for each pixel
- // that will be processed.
-
- // Based on the popup selection, a different algorithm is used
- // to generate the offset pairs.
-
- short style = rStorage -> refractorStyle;
- Rect r = rStorage -> travelRect;
- short *offsetArray;
- long width = r.right - r.left;
- long height = r.bottom - r.top;
- long numPixels = width * height;
- long row, col, hMid, vMid, x, y;
- double dist, xd, yd, angle;
-
- // In case this takes a long time.
- WatchCursor ();
-
- // For easy access.
- HLock (rStorage -> offsetBuffer);
- offsetArray = (short *)*rStorage -> offsetBuffer;
-
- // Random setting?
- if (style == 1)
- {
- style = random (3, 10);
- }
-
- // The style value corresponds to the popup menu.
- switch (style)
- {
- default:
- case eWavyGravy:
- for (row = 0; row < height; row ++)
- for (col = 0; col < width; col ++)
- {
- hMid = width / 2;
- vMid = height / 2;
- x = col - hMid;
- y = row - vMid;
- dist = sqrt (x * x + y * y);
- xd = x;
- yd = y;
-
- if (dist < hMid)
- {
- angle = - acos (xd / dist);
- if (yd > 0)
- angle = - angle;
- angle += (hMid - dist) * 2 / hMid;
-
- xd = cos (angle) * dist;
- yd = sin (angle) * dist;
-
- x = xd + hMid;
- y = yd + vMid;
- }
- else
- {
- x = col;
- y = row;
- }
-
- *(offsetArray ++) = x - col;
- *(offsetArray ++) = y - row;
- }
- break;
-
- case eHurricane:
- for (row = 0; row < height; row ++)
- for (col = 0; col < width; col ++)
- {
- hMid = width / 2;
- vMid = height / 2;
- x = col - hMid;
- y = row - vMid;
- dist = sqrt (x * x + y * y);
- xd = x;
- yd = y;
-
- if (dist < hMid)
- {
- angle = - acos (xd / dist);
- if (yd > 0)
- angle = - angle;
-
- angle += (hMid - dist) * (hMid - dist) / (hMid * sqrt(vMid));
-
- xd = cos (angle) * dist;
- yd = sin (angle) * dist;
-
- x = xd + hMid;
- y = yd + vMid;
- }
- else
- {
- x = col;
- y = row;
- }
-
- *(offsetArray ++) = x - col;
- *(offsetArray ++) = y - row;
- }
- break;
-
- case eFisheye:
- for (row = 0; row < height; row ++)
- for (col = 0; col < width; col ++)
- {
- hMid = width / 2;
- vMid = height / 2;
- x = col - hMid;
- y = row - vMid;
- dist = sqrt (x * x + y * y) + 1;
-
- if (dist < hMid)
- {
- x = x * sin ((pi * dist / 2) / hMid - pi / 2) / 1.25;
- y = y * sin ((pi * dist / 2) / hMid - pi / 2) / 1.25;
- }
- else
- {
- x = y = 0;
- }
-
- *(offsetArray ++) = x;
- *(offsetArray ++) = y;
- }
- break;
-
- case eWildDiffuser:
- for (row = 0; row < height; row ++)
- for (col = 0; col < width; col ++)
- {
- hMid = width / 2;
- vMid = height / 2;
- x = col - hMid;
- y = row - vMid;
- dist = sqrt (x * x + y * y);
-
- x = y = 0;
- if (dist < 1.0)
- dist = 1.0;
- short prob = (hMid / 2) * 2;
- if (prob)
- {
- x = random (- prob, prob);
- y = random (- prob, prob);
- x /= dist;
- y /= dist;
- }
-
- *(offsetArray ++) = x;
- *(offsetArray ++) = y;
- }
- break;
-
- case eSpectacle:
- for (row = 0; row < height; row ++)
- for (col = 0; col < width; col ++)
- {
- hMid = width / 2;
- vMid = height / 2;
- x = col - hMid;
- y = row - vMid;
- dist = sqrt (x * x + y * y) + 1;
-
- if (dist < hMid)
- {
- x = x * cos ((pi * dist / 2) / hMid);
- y = y * cos ((pi * dist / 2) / hMid);
- }
- else
- {
- x = y = 0;
- }
-
- *(offsetArray ++) = x;
- *(offsetArray ++) = y;
- }
- break;
-
- case eMagnifier:
- for (row = 0; row < height; row ++)
- for (col = 0; col < width; col ++)
- {
- hMid = width / 2;
- vMid = height / 2;
- x = (col - hMid);
- y = (row - vMid);
- dist = sqrt (x * x + y * y) + 1;
-
- if (dist > hMid)
- {
- x = y = 0;
- }
- else
- {
- x = - (col - hMid) / 2;
- y = - (row - vMid) / 2;
- }
-
- *(offsetArray ++) = x;
- *(offsetArray ++) = y;
- }
- break;
-
- case eWormhole:
- for (row = 0; row < height; row ++)
- for (col = 0; col < width; col ++)
- {
- hMid = width / 2;
- vMid = height / 2;
- x = col - hMid;
- y = row - vMid;
- dist = sqrt (x * x + y * y) + 1;
-
- if (dist < hMid)
- {
- x = x * (hMid - fabs(x)) / dist;
- y = y * (hMid - fabs(y)) / dist;
- }
- else
- {
- x = y = 0;
- }
-
- *(offsetArray ++) = x;
- *(offsetArray ++) = y;
- }
- break;
-
- case eRipple:
- for (row = 0; row < height; row ++)
- for (col = 0; col < width; col ++)
- {
- hMid = width / 2;
- vMid = height / 2;
- x = col - hMid;
- y = row - vMid;
- dist = sqrt (x * x + y * y);
- xd = x;
- yd = y;
-
- if (dist < hMid)
- {
- angle = - acos (xd / dist);
- if (yd > 0)
- angle = - angle;
-
- angle += sin ((2 * pi) * 5 * (hMid - dist) / hMid) / (2 * pi);
-
- xd = cos (angle) * dist;
- yd = sin (angle) * dist;
-
- x = xd + hMid;
- y = yd + vMid;
- }
- else
- {
- x = col;
- y = row;
- }
-
- *(offsetArray ++) = x - col;
- *(offsetArray ++) = y - row;
- }
- break;
- }
-
- HUnlock (rStorage -> offsetBuffer);
-
- // Change back from the watch cursor.
- SetCursor (¶ms -> qdGlobalsCopy -> qdArrow);
- }
-